/*
 * Copyright (c) 2020, HiHope Community.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "ohos_init.h"
#include "cmsis_os2.h"
#include "wifi_device.h"
#include "lwip/netifapi.h"
#include "lwip/api_shell.h"
#include "lwip/sockets.h"

static int g_scanDone = 0;
static int g_connected = 0;
static int g_netId = -1;

static char* SecurityTypeName(WifiSecurityType type)
{
    switch (type)
    {
    case WIFI_SEC_TYPE_OPEN:
        return "OPEN";
    case WIFI_SEC_TYPE_WEP:
        return "WEP";
    case WIFI_SEC_TYPE_PSK:
        return "PSK";
    case WIFI_SEC_TYPE_SAE:
        return "SAE";
    default:
        break;
    }
    return "unkow";
}

static void PrintLinkedInfo(WifiLinkedInfo* info)
{
    if (!info) return;

    static char macAddress[32] = {0};
    unsigned char* mac = info->bssid;
    snprintf(macAddress, sizeof(macAddress), "%02X:%02X:%02X:%02X:%02X:%02X",
        mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    printf("bssid: %s, rssi: %d, connState: %d, reason: %d, ssid: %s\r\n",
        macAddress, info->rssi, info->connState, info->disconnectedReason, info->ssid);
}
static void OnWifiConnectionChanged(int state, WifiLinkedInfo* info)
{
    if (!info) return;

    printf("%s %d, state = %d, info = \r\n", __FUNCTION__, __LINE__, state);
    PrintLinkedInfo(info);

    if (state == WIFI_STATE_AVALIABLE) {
        g_connected = 1;
    } else {
        g_connected = 0;
    }
}

void PrintScanResult(void)
{
    WifiScanInfo scanResult[WIFI_SCAN_HOTSPOT_LIMIT] = {0};
    uint32_t resultSize = WIFI_SCAN_HOTSPOT_LIMIT;

    memset(&scanResult, 0, sizeof(scanResult));
    WifiErrorCode errCode = GetScanInfoList(scanResult, &resultSize);
    if (errCode != WIFI_SUCCESS) {
        printf("GetScanInfoList failed: %d\r\n", errCode);
    }
    for (uint32_t i = 0; i < resultSize; i++) {
        static char macAddress[32] = {0};
        WifiScanInfo info = scanResult[i];
        unsigned char* mac = info.bssid;
        snprintf(macAddress, sizeof(macAddress), "%02X:%02X:%02X:%02X:%02X:%02X", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
        printf("Result[%d]: %s, % 4s, %d, %d, %d, %s\r\n", i, macAddress, SecurityTypeName(info.securityType), info.rssi, info.band, info.frequency, info.ssid);
    }
}



void OnWifiScanStateChanged(int state, int size)
{
    printf("%s %d, state = %X, size = %d\r\n", __FUNCTION__, __LINE__, state, size);

    if (state == WIFI_STATE_AVALIABLE && size > 0) {
        g_scanDone = 1;
    }
}

WifiEvent g_eventListener = {
    .OnWifiConnectionChanged = OnWifiConnectionChanged,
    .OnWifiScanStateChanged = OnWifiScanStateChanged
};
static void WifiConnet(void )
{
    WifiErrorCode errCode;
    WifiDeviceConfig apConfig = {};

    osDelay(10);
    errCode = RegisterWifiEvent(&g_eventListener);
    printf("RegisterWifiEvent: %d\r\n", errCode);

    // setup your AP params
    strcpy(apConfig.ssid, "Yourwifi");
    strcpy(apConfig.preSharedKey, "Yourpasswd");
    apConfig.securityType = WIFI_SEC_TYPE_PSK;

    errCode = EnableWifi();
    printf("EnableWifi: %d\r\n", errCode);
    osDelay(100);

    g_scanDone = 0;
    errCode = Scan();
    printf("Scan: %d\r\n", errCode);
    

    // wait for scan done!
    while (!g_scanDone) {
        osDelay(5);
    }
    PrintScanResult();

    errCode = AddDeviceConfig(&apConfig, &g_netId);
    printf("AddDeviceConfig: %d\r\n", errCode);

    g_connected = 0;
    errCode = ConnectTo(g_netId);
    printf("ConnectTo(%d): %d\r\n", g_netId, errCode);

    while (!g_connected) {
        osDelay(10);
    }
    printf("g_connected: %d\r\n", g_connected);
    osDelay(50);

    // 联网业务开始
    // 这里是网络业务代码...
    struct netif* iface = netifapi_netif_find("wlan0");
    if (iface) {
        err_t ret = netifapi_dhcp_start(iface);
        printf("netifapi_dhcp_start: %d\r\n", ret);

        osDelay(200); // wait DHCP server give me IP
        ret = netifapi_netif_common(iface, dhcp_clients_info_show, NULL);
        printf("netifapi_netif_common: %d\r\n", ret);
    }

   


}

static void WifiDisconnet(void )
{
    WifiErrorCode errCode;
            
    Disconnect(); // disconnect with your AP  
    printf("Disconnect ok");      
    RemoveDevice(g_netId); // remove AP config        
    errCode = DisableWifi();        
    printf("DisableWifi: %d\r\n", errCode);
    osDelay(500);
    

}

static int TcpClient(void)
{
    struct sockaddr_in server_addr = {0};
    int sock_fd;


    if((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
		printf("socket error");
		return -1;
	}

    server_addr.sin_family = AF_INET;
    //服务器的端口号
	server_addr.sin_port = htons(1234);
	//写入服务器地址
	server_addr.sin_addr.s_addr = inet_addr("192.168.3.12");

    if(connect(sock_fd,(struct sockaddr *)&server_addr,sizeof(struct sockaddr)) == -1)
    { 
        printf("connect error");
        return -2;
    }

    printf("connect success!!\r\n");
    osDelay(100);
    while(1)
    {
        char buf[32] = "hello I'm client\r\n";
        int len = strlen(buf) + 1;

        send(sock_fd, buf, len, 0);

        memset(buf, 0, sizeof(buf));

        recv(sock_fd, buf, sizeof(buf), 0);

        if(buf[0] == '0')
        {
            printf("say good bye\r\n");
            break;
        }
        else
        {
            printf("server:[%s]",buf);
        }
    }
    
    closesocket(sock_fd);
    printf("close the socket!\r\n");

    
    return 0;


}

static void WifiClientTask(void *arg)
{
    (void)arg;
   

    WifiConnet();
    TcpClient();
    WifiDisconnet();

    
    

}

static void TcpClientDemo(void)
{
    osThreadAttr_t attr;

    attr.name = "WifiClientTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 10240;
    attr.priority = osPriorityNormal;

    if (osThreadNew(WifiClientTask, NULL, &attr) == NULL) {
        printf("[TcpClientDemo] Falied to create WifiScanTask!\n");
    }
}

APP_FEATURE_INIT(TcpClientDemo);

